package service

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os/exec"
	"runtime"
	"sync"
	"time"

	"github.com/google/uuid"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
	"skedule-backend/config"
	"skedule-backend/database"
	"skedule-backend/types"
	"skedule-backend/utils"
)

// debugLog 只在调试模式下打印日志
func debugLog(format string, args ...interface{}) {
	if config.IsDebugMode() {
		fmt.Printf("[TaskExecution] "+format+"\n", args...)
	}
}

// ExecutionContext 执行上下文
type ExecutionContext struct {
	Execution *types.TaskExecution
	Cancel    context.CancelFunc
	Cmd       *exec.Cmd
}

// TaskExecutionService 任务执行服务
type TaskExecutionService struct {
	executions sync.Map // 存储执行记录，key 为 executionId
	tasks      sync.Map // 存储任务信息，key 为 taskId
	contexts   sync.Map // 存储执行上下文，key 为 executionId
	wsHandler  WSHandler // WebSocket处理器接口
}

// WSHandler WebSocket处理器接口
type WSHandler interface {
	BroadcastTaskEvent(eventType string, task interface{})
	BroadcastLogEvent(log interface{})
	BroadcastSystemEvent(event string, data interface{})
}

// NewTaskExecutionService 创建任务执行服务实例
func NewTaskExecutionService() *TaskExecutionService {
	return &TaskExecutionService{}
}

// SetWSHandler 设置WebSocket处理器
func (s *TaskExecutionService) SetWSHandler(wsHandler WSHandler) {
	s.wsHandler = wsHandler
}

// ExecuteTask 执行任务
func (s *TaskExecutionService) ExecuteTask(taskID string) (*types.ExecuteTaskResponse, error) {
	// 获取任务信息
	taskObj, exists := s.tasks.Load(taskID)
	if !exists {
		return nil, fmt.Errorf("task not found: %s", taskID)
	}
	task := taskObj.(*types.Task)

	// 检查任务是否已在运行
	if task.Running {
		return nil, fmt.Errorf("task is already running")
	}

	// 生成执行ID
	executionID := uuid.New().String()

	// 创建执行记录
	execution := &types.TaskExecution{
		ID:        executionID,
		TaskID:    taskID,
		TaskName:  task.Name,
		StartTime: time.Now(),
		EndTime:   nil,
		Status:    "running",
		Output:    "",
	}

	// 存储执行记录
	s.executions.Store(executionID, execution)

	// 立即保存初始执行记录到数据库（running状态）
	s.saveExecutionToDB(execution)

	// 更新任务状态
	task.Running = true
	task.ExecutionID = executionID
	s.tasks.Store(taskID, task)

	// 同步运行状态到数据库
	database.UpdateTaskRunningStatus(taskID, true)

	// 异步执行命令
	go s.runCommand(execution, task.Command)

	return &types.ExecuteTaskResponse{
		Success:     true,
		ExecutionID: executionID,
	}, nil
}

// StopTask 停止任务
func (s *TaskExecutionService) StopTask(taskID string) (*types.ExecuteTaskResponse, error) {
	// 获取任务信息
	taskObj, exists := s.tasks.Load(taskID)
	if !exists {
		return nil, fmt.Errorf("task not found: %s", taskID)
	}
	task := taskObj.(*types.Task)

	// 检查任务是否正在运行
	if !task.Running || task.ExecutionID == "" {
		return nil, fmt.Errorf("task is not running")
	}

	// 获取执行上下文
	ctxObj, exists := s.contexts.Load(task.ExecutionID)
	if !exists {
		return nil, fmt.Errorf("execution context not found")
	}
	
	execCtx := ctxObj.(*ExecutionContext)
	
	// 取消命令执行
	if execCtx.Cancel != nil {
		execCtx.Cancel()
	}

	// 强制杀死进程（如果还在运行）
	if execCtx.Cmd != nil && execCtx.Cmd.Process != nil {
		execCtx.Cmd.Process.Kill()
	}

	// 更新执行记录
	if execObj, exists := s.executions.Load(task.ExecutionID); exists {
		execution := execObj.(*types.TaskExecution)
		execution.Status = "stopped"
		now := time.Now()
		execution.EndTime = &now
		execution.Duration = execution.EndTime.Sub(execution.StartTime).Milliseconds()
		execution.Output += "\n\n" + utils.T("task.execution.stopped")
		s.executions.Store(task.ExecutionID, execution)
		
		// 保存执行记录到数据库
		s.saveExecutionToDB(execution)
	}

	// 更新任务状态
	task.Running = false
	task.ExecutionID = ""
	s.tasks.Store(taskID, task)

	// 同步运行状态到数据库
	database.UpdateTaskRunningStatus(taskID, false)
	
	// 同步LastRun时间到数据库（使用执行开始时间）
	if execObj, exists := s.executions.Load(task.ExecutionID); exists {
		execution := execObj.(*types.TaskExecution)
		task.LastRun = types.CustomTime{Time: execution.StartTime}
		s.tasks.Store(taskID, task)
		
		if err := database.UpdateTaskLastRun(taskID, execution.StartTime); err != nil {
			debugLog(utils.T("task.debug.lastrun.update.failed"), taskID, err)
		} else {
			debugLog(utils.T("task.debug.lastrun.update.success"), taskID, execution.StartTime.Format("2006-01-02 15:04:05"))
		}
	}

	// 清理执行上下文
	s.contexts.Delete(task.ExecutionID)

	return &types.ExecuteTaskResponse{
		Success: true,
		Message: "Task stopped successfully",
	}, nil
}

// GetExecution 获取执行记录
func (s *TaskExecutionService) GetExecution(executionID string) (*types.ExecutionResponse, error) {
	execObj, exists := s.executions.Load(executionID)
	if !exists {
		return nil, fmt.Errorf("execution not found: %s", executionID)
	}

	execution := execObj.(*types.TaskExecution)
	
	// 如果任务正在运行，更新执行时长
	if execution.Status == "running" {
		execution.Duration = time.Since(execution.StartTime).Milliseconds()
	}

	return &types.ExecutionResponse{
		Success: true,
		Data:    *execution,
	}, nil
}

// runCommand 执行命令并实时更新输出
func (s *TaskExecutionService) runCommand(execution *types.TaskExecution, command string) {
	// 创建上下文，用于取消命令执行
	ctx, cancel := context.WithCancel(context.Background())
	
	// 检查命令是否为空
	if command == "" {
		execution.Status = "error"
		execution.Output = utils.T("task.execution.command.empty")
		now := time.Now()
		execution.EndTime = &now
		execution.Duration = execution.EndTime.Sub(execution.StartTime).Milliseconds()
		s.executions.Store(execution.ID, execution)
		s.saveExecutionToDB(execution)
		cancel()
		return
	}
	
	// 根据操作系统准备命令
	var cmd *exec.Cmd
	switch runtime.GOOS {
	case "windows":
		// Windows系统：通过cmd.exe执行命令，支持内置命令如echo、dir等
		cmd = exec.CommandContext(ctx, "cmd", "/C", command)
	case "darwin":
		// macOS系统：优先使用bash，如果不存在则使用sh
		if _, err := exec.LookPath("bash"); err == nil {
			cmd = exec.CommandContext(ctx, "bash", "-c", command)
		} else {
			cmd = exec.CommandContext(ctx, "sh", "-c", command)
		}
	case "linux":
		// Linux系统：优先使用bash，如果不存在则使用sh
		if _, err := exec.LookPath("bash"); err == nil {
			cmd = exec.CommandContext(ctx, "bash", "-c", command)
		} else {
			cmd = exec.CommandContext(ctx, "sh", "-c", command)
		}
	case "freebsd", "openbsd", "netbsd":
		// BSD系统：使用sh
		cmd = exec.CommandContext(ctx, "sh", "-c", command)
	case "solaris":
		// Solaris系统：使用sh
		cmd = exec.CommandContext(ctx, "sh", "-c", command)
	default:
		// 其他Unix-like系统：默认使用sh
		cmd = exec.CommandContext(ctx, "sh", "-c", command)
	}
	
	// 创建执行上下文
	execCtx := &ExecutionContext{
		Execution: execution,
		Cancel:    cancel,
		Cmd:       cmd,
	}
	s.contexts.Store(execution.ID, execCtx)

	// 创建管道获取输出
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		execution.Status = "error"
		execution.Output = fmt.Sprintf("Failed to create stdout pipe: %v", err)
		now := time.Now()
		execution.EndTime = &now
		execution.Duration = execution.EndTime.Sub(execution.StartTime).Milliseconds()
		s.executions.Store(execution.ID, execution)
		s.contexts.Delete(execution.ID)
		cancel()
		return
	}

	stderr, err := cmd.StderrPipe()
	if err != nil {
		execution.Status = "error"
		execution.Output = fmt.Sprintf("Failed to create stderr pipe: %v", err)
		now := time.Now()
		execution.EndTime = &now
		execution.Duration = execution.EndTime.Sub(execution.StartTime).Milliseconds()
		s.executions.Store(execution.ID, execution)
		s.contexts.Delete(execution.ID)
		cancel()
		return
	}

	// 开始执行命令
	if err := cmd.Start(); err != nil {
		execution.Status = "error"
		execution.Output = fmt.Sprintf("Failed to start command: %v", err)
		now := time.Now()
		execution.EndTime = &now
		execution.Duration = execution.EndTime.Sub(execution.StartTime).Milliseconds()
		s.executions.Store(execution.ID, execution)
		s.contexts.Delete(execution.ID)
		cancel()
		return
	}

	// 添加执行环境信息到输出
	execution.Output += utils.T("task.execution.started") + "\n"
	execution.Output += fmt.Sprintf(utils.T("task.execution.env") + "\n", getShellInfo())
	execution.Output += fmt.Sprintf(utils.T("task.execution.os") + "\n", runtime.GOOS, runtime.GOARCH)
	execution.Output += fmt.Sprintf(utils.T("task.execution.command") + "\n", command)
	execution.Output += fmt.Sprintf(utils.T("task.execution.start.time") + "\n", execution.StartTime.Format("2006-01-02 15:04:05"))
	execution.Output += fmt.Sprintf("==================\n\n")
	s.executions.Store(execution.ID, execution)

	// 推送执行开始事件
	if s.wsHandler != nil {
		debugLog(utils.T("task.debug.websocket.start"), execution.ID)
		s.wsHandler.BroadcastLogEvent(map[string]interface{}{
			"type":        "execution_started",
			"executionId": execution.ID,
			"taskId":      execution.TaskID,
			"fullOutput":  execution.Output,
			"status":      execution.Status,
			"timestamp":   time.Now(),
		})
	}

	// 读取输出
	go s.readOutput(stdout, execution)
	go s.readOutput(stderr, execution)

	// 等待命令完成
	err = cmd.Wait()
	nowAfterWait := time.Now()
	execution.EndTime = &nowAfterWait
	execution.Duration = execution.EndTime.Sub(execution.StartTime).Milliseconds()

	// 检查是否被取消
	select {
	case <-ctx.Done():
		if execution.Status != "stopped" { // 如果不是手动停止，则是超时或其他原因
			execution.Status = "cancelled"
			execution.Output += "\n\nCommand was cancelled"
		}
	default:
		if err != nil {
			execution.Status = "error"
			execution.Output += fmt.Sprintf("\nCommand failed: %v", err)
		} else {
			execution.Status = "success"
			execution.Output += "\nCommand completed successfully"
		}
	}

	// 更新执行记录
	s.executions.Store(execution.ID, execution)

	// 推送执行完成事件
	if s.wsHandler != nil {
		debugLog(utils.T("task.debug.websocket.complete"), execution.ID, execution.Status)
		s.wsHandler.BroadcastLogEvent(map[string]interface{}{
			"type":        "execution_completed",
			"executionId": execution.ID,
			"taskId":      execution.TaskID,
			"fullOutput":  execution.Output,
			"status":      execution.Status,
			"duration":    execution.Duration,
			"timestamp":   time.Now(),
		})
	}

	// 保存执行记录到数据库
	s.saveExecutionToDB(execution)

	// 更新任务状态
	if taskObj, exists := s.tasks.Load(execution.TaskID); exists {
		task := taskObj.(*types.Task)
		task.Running = false
		task.ExecutionID = ""
		task.LastRun = types.CustomTime{Time: execution.StartTime}
		s.tasks.Store(execution.TaskID, task)
		
		// 同步运行状态到数据库
		database.UpdateTaskRunningStatus(execution.TaskID, false)
		
		// 同步LastRun时间到数据库
		if err := database.UpdateTaskLastRun(execution.TaskID, execution.StartTime); err != nil {
			debugLog(utils.T("task.debug.lastrun.update.failed"), execution.TaskID, err)
		} else {
			debugLog(utils.T("task.debug.lastrun.update.success"), execution.TaskID, execution.StartTime.Format("2006-01-02 15:04:05"))
		}
	}

	// 清理执行上下文
	s.contexts.Delete(execution.ID)
	cancel()
}

// readOutput 读取命令输出
func (s *TaskExecutionService) readOutput(r io.Reader, execution *types.TaskExecution) {
	debugLog(utils.T("task.debug.output.reading.start"), execution.ID)
	
	// 在Windows上将GBK编码转换为UTF-8
	var reader io.Reader = r
	if runtime.GOOS == "windows" {
		decoder := simplifiedchinese.GBK.NewDecoder()
		reader = transform.NewReader(r, decoder)
	}
	
	scanner := bufio.NewScanner(reader)
	lineCount := 0
	
	for scanner.Scan() {
		line := scanner.Text()
		lineCount++
		debugLog(utils.T("task.debug.output.line"), lineCount, execution.ID, line)
		
		// 使用互斥锁保护输出更新，避免竞态条件
		if execObj, exists := s.executions.Load(execution.ID); exists {
			exec := execObj.(*types.TaskExecution)
			exec.Output += line + "\n"
			s.executions.Store(execution.ID, exec)
			
			// 通过WebSocket实时推送输出更新
			if s.wsHandler != nil {
				debugLog(utils.T("task.debug.websocket.output"), execution.ID, line)
				s.wsHandler.BroadcastLogEvent(map[string]interface{}{
					"type":        "output_update",
					"executionId": execution.ID,
					"taskId":      execution.TaskID,
					"newLine":     line,
					"fullOutput":  exec.Output,
					"status":      exec.Status,
					"timestamp":   time.Now(),
				})
			} else {
				debugLog(utils.T("task.debug.websocket.empty"))
			}
		} else {
			debugLog(utils.T("task.debug.execution.notfound"), execution.ID)
		}
	}
	
	if err := scanner.Err(); err != nil {
		debugLog(utils.T("task.debug.output.error"), execution.ID, err)
	}
	
	debugLog(utils.T("task.debug.output.complete"), execution.ID, lineCount)
}

// UpdateTask 更新任务信息
func (s *TaskExecutionService) UpdateTask(task *types.Task) {
	s.tasks.Store(task.ID, task)
}

// GetTask 获取任务信息
func (s *TaskExecutionService) GetTask(taskID string) (*types.Task, bool) {
	if taskObj, exists := s.tasks.Load(taskID); exists {
		return taskObj.(*types.Task), true
	}
	return nil, false
}

// DeleteTask 删除任务信息
func (s *TaskExecutionService) DeleteTask(taskID string) {
	s.tasks.Delete(taskID)
}

// saveExecutionToDB 保存执行记录到数据库
func (s *TaskExecutionService) saveExecutionToDB(execution *types.TaskExecution) {
	// 获取任务信息以获取任务名称
	taskName := execution.TaskName
	if taskName == "" {
		taskName = "Unknown Task (from execution)"
	}

	// 计算退出码（简化处理）
	var exitCode int
	if execution.Status == "success" {
		exitCode = 0
	} else {
		exitCode = 1
	}

	// 创建数据库日志记录
	dbLog := &database.TaskLog{
		TaskID:    execution.TaskID,
		TaskName:  taskName,
		Status:    execution.Status,
		Output:    execution.Output,
		StartTime: execution.StartTime,
		Duration:  execution.Duration,
		ExitCode:  exitCode,
		Error:     "", // 如果需要可以从Output中提取错误信息
		CreatedAt: time.Now(),
	}

	if execution.EndTime != nil {
		dbLog.EndTime = execution.EndTime
	}

	// 尝试查找已存在的记录（基于TaskID和StartTime）
	var existingLog database.TaskLog
	err := database.DB.Where("task_id = ? AND start_time = ?", execution.TaskID, execution.StartTime).First(&existingLog).Error
	
	if err == nil {
		// 记录已存在，更新它
		dbLog.ID = existingLog.ID
		dbLog.CreatedAt = existingLog.CreatedAt // 保持原创建时间
		// 更新 EndTime 的逻辑也需要适配指针
		if execution.EndTime != nil {
		    dbLog.EndTime = execution.EndTime
		} else {
		    dbLog.EndTime = nil // 确保如果 execution.EndTime 是零值，数据库中存 nil
		}
		if err := database.DB.Save(dbLog).Error; err != nil {
			fmt.Printf("Failed to update execution log in database: %v\n", err)
		}
	} else {
		// 记录不存在，创建新记录
		if err := database.CreateTaskLog(dbLog); err != nil {
			fmt.Printf("Failed to create execution log in database: %v\n", err)
		}
	}
}

// getShellInfo 获取当前系统的shell信息，用于调试和日志记录
func getShellInfo() string {
	switch runtime.GOOS {
	case "windows":
		return "Windows CMD"
	case "darwin":
		if _, err := exec.LookPath("bash"); err == nil {
			return "macOS Bash"
		}
		return "macOS Shell"
	case "linux":
		if _, err := exec.LookPath("bash"); err == nil {
			return "Linux Bash"
		}
		return "Linux Shell"
	case "freebsd":
		return "FreeBSD Shell"
	case "openbsd":
		return "OpenBSD Shell"
	case "netbsd":
		return "NetBSD Shell"
	case "solaris":
		return "Solaris Shell"
	default:
		return fmt.Sprintf("Unknown OS (%s) Shell", runtime.GOOS)
	}
} 